home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Tech Arsenal 1
/
Tech Arsenal (Arsenal Computer).ISO
/
tek-04
/
ms_sh21s.zip
/
SH210
/
SRC
/
SH8.C
< prev
next >
Wrap
C/C++ Source or Header
|
1992-12-14
|
18KB
|
945 lines
/* MS-DOS SHELL - Unix File I/O Emulation
*
* MS-DOS SHELL - Copyright (c) 1990,1,2 Data Logic Limited
*
* This code is subject to the following copyright restrictions:
*
* 1. Redistribution and use in source and binary forms are permitted
* provided that the above copyright notice is duplicated in the
* source form and the copyright notice in file sh6.c is displayed
* on entry to the program.
*
* 2. The sources (or parts thereof) or objects generated from the sources
* (or parts of sources) cannot be sold under any circumstances.
*
* $Header: /usr/users/istewart/src/shell/sh2.1/RCS/sh8.c,v 2.4 1992/12/14 10:54:56 istewart Exp $
*
* $Log: sh8.c,v $
* Revision 2.4 1992/12/14 10:54:56 istewart
* BETA 215 Fixes and 2.1 Release
*
* Revision 2.3 1992/11/06 10:03:44 istewart
* 214 Beta test updates
*
* Revision 2.2 1992/07/16 14:33:34 istewart
* Beta 212 Baseline
*
* Revision 2.1 1992/07/10 10:52:48 istewart
* 211 Beta updates
*
* Revision 2.0 1992/04/13 17:39:09 Ian_Stewartson
* MS-Shell 2.0 Baseline release
*
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <signal.h>
#include <errno.h>
#include <setjmp.h>
#include <stdlib.h>
#include <fcntl.h>
#include <stdarg.h>
#include <string.h>
#include <unistd.h>
#include <limits.h>
#include <dirent.h>
#include <ctype.h>
#ifdef OS2
#define INCL_DOSSESMGR
#include <os2.h> /* DOS functions declarations */
#else
#include <dos.h> /* DOS functions declarations */
#endif
#include "sh.h"
#define F_START 4
static char *nopipe = "can't create pipe - try again\n";
/* List of open files to allow us to simulate the Unix open and unlink
* operation for temporary files
*/
typedef struct flist {
struct flist *fl_next; /* Next link */
char *fl_name; /* File name */
bool fl_close; /* Delete on close flag */
int fl_size; /* Size of fl_fd array */
int fl_count; /* Number of entries in array */
int fl_mode; /* File open mode */
int *fl_fd; /* File ID array (for dup) */
} s_flist;
static s_flist *list_start = (s_flist *)NULL;
static s_flist *near find_entry (int);
/*
* Open a file and add it to the Open file list. Errors are the same as
* for a normal open.
*/
int S_open (bool d_flag, char *name, int mode, ...)
{
va_list ap;
int pmask;
s_flist *fp = (s_flist *)NULL;
int *f_list = (int *)NULL;
char *f_name = (char *)NULL;
void (*save_signal)(int);
/* Check the permission mask if it exists */
va_start (ap, mode);
pmask = va_arg (ap, int);
va_end (ap);
/* Check this is a valid file name */
CheckDOSFileName (name);
/* Grap some space. If it fails, free space and return an error */
if (((fp = (s_flist *) GetAllocatedSpace (sizeof (s_flist)))
== (s_flist *)NULL) ||
((f_list = (int *) GetAllocatedSpace (sizeof (int) * F_START))
== (int *)NULL) ||
((f_name = StringSave (name)) == null))
{
if (f_list == (int *)NULL)
ReleaseMemoryCell ((void *)f_list);
if (fp == (s_flist *)NULL)
ReleaseMemoryCell ((void *)fp);
errno = ENOMEM;
return -1;
}
/* Disable signals */
save_signal = signal (SIGINT, SIG_IGN);
/* Set up the structure. Change two Unix device names to the DOS
* equivalents and disable create
*/
if (strnicmp (name, DeviceNameHeader, LEN_DEVICE_NAME_HEADER) == 0)
{
if (stricmp (&name[5], "tty") == 0)
strcpy (&name[5], "con");
else if (stricmp (&name[5], "null") == 0)
strcpy (&name[5], "nul");
mode &= ~(O_CREAT | O_TRUNC);
}
fp->fl_name = strcpy (f_name, name);
fp->fl_close = d_flag;
fp->fl_size = F_START;
fp->fl_count = 1;
fp->fl_fd = f_list;
fp->fl_mode = mode;
/* Open the file */
if ((fp->fl_fd[0] = open (name, mode, pmask)) < 0)
{
pmask = errno;
ReleaseMemoryCell ((void *)f_name);
ReleaseMemoryCell ((void *)f_list);
ReleaseMemoryCell ((void *)fp);
errno = pmask;
pmask = -1;
}
/* Make sure everything is in area 0 */
else
{
SetMemoryAreaNumber ((void *)fp, 0);
SetMemoryAreaNumber ((void *)f_list, 0);
/* List into the list */
fp->fl_next = list_start;
list_start = fp;
/* Return the file descriptor */
pmask = fp->fl_fd[0];
}
/* Restore signals */
signal (SIGINT, save_signal);
return pmask;
}
/*
* Scan the File list for the appropriate entry for the specified ID
*/
static s_flist * near find_entry (int fid)
{
s_flist *fp = list_start;
int i;
while (fp != (s_flist *)NULL)
{
for (i = 0; i < fp->fl_count; i++)
{
if (fp->fl_fd[i] == fid)
return fp;
}
fp = fp->fl_next;
}
return (s_flist *)NULL;
}
/* Close the file
*
* We need a version of close that does everything but close for dup2 as
* new file id is closed. If c_flag is TRUE, close the file as well.
*/
int S_close (int fid, bool c_flag)
{
s_flist *fp = find_entry (fid);
s_flist *last = (s_flist *)NULL;
s_flist *fp1 = list_start;
int i, serrno;
bool release = TRUE;
bool delete = FALSE;
char *fname;
void (*save_signal)(int);
/* Disable signals */
save_signal = signal (SIGINT, SIG_IGN);
/* Find the entry for this ID */
if (fp != (s_flist *)NULL)
{
for (i = 0; i < fp->fl_count; i++)
{
if (fp->fl_fd[i] == fid)
fp->fl_fd[i] = -1;
if (fp->fl_fd[i] != -1)
release = FALSE;
}
/* Are all the Fids closed ? */
if (release)
{
fname = fp->fl_name;
delete = fp->fl_close;
ReleaseMemoryCell ((void *)fp->fl_fd);
/* Scan the list and remove the entry */
while (fp1 != (s_flist *)NULL)
{
if (fp1 != fp)
{
last = fp1;
fp1 = fp1->fl_next;
continue;
}
if (last == (s_flist *)NULL)
list_start = fp->fl_next;
else
last->fl_next = fp->fl_next;
break;
}
/* OK - delete the area */
ReleaseMemoryCell ((void *)fp);
}
}
/* Flush these two in case they were re-directed */
fflush (stdout);
fflush (stderr);
/* Close the file anyway */
if (c_flag)
{
i = close (fid);
serrno = errno;
}
/* Delete the file ? */
if (delete)
{
unlink (fname);
ReleaseMemoryCell ((void *)fname);
}
/* Restore signals */
signal (SIGINT, save_signal);
/* Restore results and error code */
errno = serrno;
return i;
}
/*
* Duplicate file handler. Add the new handler to the ID array for this
* file.
*/
int S_dup (int old_fid)
{
int new_fid;
if ((new_fid = dup (old_fid)) >= 0)
S_Remap (old_fid, new_fid);
return new_fid;
}
/*
* Add the ID to the ID array for this file
*/
int S_Remap (int old_fid, int new_fid)
{
s_flist *fp = find_entry (old_fid);
int *flist;
int i;
if (fp == (s_flist *)NULL)
return new_fid;
/* Is there an empty slot ? */
for (i = 0; i < fp->fl_count; i++)
{
if (fp->fl_fd[i] == -1)
return (fp->fl_fd[i] = new_fid);
}
/* Is there any room at the end ? No - grap somemore space and effect a
* re-alloc. What to do if the re-alloc fails - should really get here.
* Safty check only??
*/
if (fp->fl_count == fp->fl_size)
{
if ((flist = (int *) GetAllocatedSpace ((fp->fl_size + F_START) *
sizeof (int))) == (int *)NULL)
return new_fid;
SetMemoryAreaNumber ((void *)flist, 0);
memcpy ((char *)flist, (char *)fp->fl_fd, sizeof (int) * fp->fl_size);
ReleaseMemoryCell ((void *)fp->fl_fd);
fp->fl_fd = flist;
fp->fl_size += F_START;
}
return (fp->fl_fd[fp->fl_count++] = new_fid);
}
/*
* Set Delete on Close flag
*/
void S_Delete (int fid)
{
s_flist *fp = find_entry (fid);
if (fp != (s_flist *)NULL)
fp->fl_close = TRUE;
}
/*
* Duplicate file handler onto specific handler
*/
int S_dup2 (int old_fid, int new_fid)
{
int res = -1;
int i;
Save_IO *sp;
/* If duping onto stdin, stdout or stderr, Search the Save IO stack for an
* entry matching us
*/
if ((new_fid >= STDIN_FILENO) && (new_fid <= STDERR_FILENO))
{
for (sp = SSave_IO, i = 0; (i < NSave_IO_E) &&
(SSave_IO[i].depth < Execute_stack_depth);
i++);
/* If depth is greater the Execute_stack_depth - we should panic as this
* should not happen. However, for the moment, I'll ignore it
*/
/* If there an entry for this depth ? */
if (i == NSave_IO_E)
{
/* Do we need more space? */
if (NSave_IO_E == MSave_IO_E)
{
sp = (Save_IO *)GetAllocatedSpace ((MSave_IO_E + SSAVE_IO_SIZE)
* sizeof (Save_IO));
/* Check for error */
if (sp == (Save_IO *)NULL)
return -1;
/* Save original data */
if (MSave_IO_E != 0)
{
memcpy (sp, SSave_IO, sizeof (Save_IO) * MSave_IO_E);
ReleaseMemoryCell ((void *)SSave_IO);
}
SetMemoryAreaNumber ((void *)sp, 1);
SSave_IO = sp;
MSave_IO_E += SSAVE_IO_SIZE;
}
/* Initialise the new entry */
sp = &SSave_IO[NSave_IO_E++];
sp->depth = Execute_stack_depth;
sp->fp[STDIN_FILENO] = -1;
sp->fp[STDOUT_FILENO] = -1;
sp->fp[STDERR_FILENO] = -1;
}
if (sp->fp[new_fid] == -1)
sp->fp[new_fid] = ReMapIOHandler (new_fid);
fflush (stdout);
fflush (stderr);
}
/* OK - Dup the descriptor */
if ((old_fid != -1) && ((res = dup2 (old_fid, new_fid)) >= 0))
{
S_close (new_fid, FALSE);
res = S_Remap (old_fid, new_fid);
}
return res;
}
/*
* Restore the Stdin, Stdout and Stderr to original values. If change is
* FALSE, just remove entries from stack. A special case for exec.
*/
int RestoreStandardIO (int rv, bool change)
{
int j, i;
Save_IO *sp;
/* Start at the top and remove any entries above the current execute stack
* depth
*/
for (j = NSave_IO_E; j > 0; j--)
{
sp = &SSave_IO[j - 1];
if (sp->depth < Execute_stack_depth)
break;
/* Reduce number of entries */
--NSave_IO_E;
/* If special case (changed at this level) - continue */
if (!change && (sp->depth == Execute_stack_depth))
continue;
/* Close and restore any files */
for (i = STDIN_FILENO; i <= STDERR_FILENO; i++)
{
if (sp->fp[i] != -1)
{
S_close (i, TRUE);
dup2 (sp->fp[i], i);
S_close (sp->fp[i], TRUE);
}
}
}
return rv;
}
/*
* Create a Pipe
*/
int OpenAPipe (void)
{
register int i;
if ((i = S_open (TRUE, GenerateTemporaryFileName (), O_PMASK, 0600)) < 0)
PrintErrorMessage (nopipe);
return i;
}
/*
* Close a pipe
*/
void CloseThePipe (register int pv)
{
if (pv != -1)
S_close (pv, TRUE);
}
/*
* Check for restricted shell
*/
bool CheckForRestrictedShell (char *s)
{
if (RestrictedShellFlag)
{
PrintErrorMessage (BasicErrorMessage, s, "restricted");
return TRUE;
}
return FALSE;
}
/*
* Check to see if a file is a shell script. If it is, return the file
* handler for the file
*/
int OpenForExecution (char *path, char **params, int *nargs)
{
int i = -1;
char *local_path;
/* Work on a copy of the path */
if ((local_path = AllocateMemoryCell (strlen (path) + 4)) == (char *)NULL)
return -1;
/* Try the file name and then with a .sh appended */
if ((i = CheckForScriptFile (strcpy (local_path, path), params, nargs)) < 0)
i = CheckForScriptFile (strcat (local_path, SHELLExtension), params,
nargs);
ReleaseMemoryCell ((void *)local_path);
return i;
}
/*
* Check for shell script
*/
int CheckForScriptFile (char *path, char **params, int *nargs)
{
char buf[512]; /* Input buffer */
int fp; /* File handler */
int nbytes; /* Number of bytes read */
char *bp; /* Pointers into buffers */
char *ep;
if ((fp = S_open (FALSE, path, O_RMASK)) < 0)
return -1;
/* zero or less bytes - not a script */
memset (buf, 0, 512);
nbytes = read (fp, buf, 512);
for (ep = &buf[nbytes], bp = buf; (bp < ep) && ((unsigned char)*bp >= 0x08); ++bp);
/* If non-ascii file or lenght is less than 1 - not a script */
if ((bp != ep) || (nbytes < 1))
{
S_close (fp, TRUE);
return -1;
}
/* Ensure end of buffer detected */
buf[511] = 0;
/* Initialise the return parameters, if specified */
if (params != (char **)NULL)
*params = null;
if (nargs != (int *)NULL)
*nargs = 0;
/* We don't care how many bytes were read now, so use it to count the
* additional arguments
*/
nbytes = 0;
/* Find the end of the first line */
if ((bp = strchr (buf, '\n')) != (char *)NULL)
*bp = 0;
bp = buf;
ep = (char *)NULL;
/* Check for script */
if ((*(bp++) != '#') || (*(bp++) != '!'))
return fp;
while (*bp)
{
while (isspace (*bp))
++bp;
/* Save the start of the arguments */
if (*bp)
{
if (ep == (char *)NULL)
ep = bp;
/* Count the arguments */
++nbytes;
}
while (!isspace (*bp) && *bp)
++bp;
}
/* Set up the return parameters, if appropriate */
if ((params != (char **)NULL) && (strlen (ep) != 0))
{
if ((*params = AllocateMemoryCell (strlen (ep) + 1)) == (char *)NULL)
{
*params = null;
S_close (fp, TRUE);
return -1;
}
strcpy (*params, ep);
}
if (nargs != (int *)NULL)
*nargs = nbytes;
return fp;
}
/*
* The specified file handler the console
*/
bool IsConsole (int fp)
{
#ifdef OS2
USHORT fsType;
USHORT usDeviceAttr;
DosQHandType (fp, &fsType, &usDeviceAttr);
/* The value 0x8083 seems to be the value returned by the console */
return (LOBYTE (fsType) == HANDTYPE_DEVICE) && (usDeviceAttr == 0x8083)
? TRUE : FALSE;
#else
union REGS r;
r.x.ax = 0x4400;
r.x.bx = fp;
intdos (&r, &r);
return ((r.x.dx & 0x0081) == 0x0081) ? TRUE : FALSE;
#endif
}
/*
* Get the current drive number
*/
unsigned int GetCurrentDrive (void)
{
#ifdef OS2
ULONG ulDrives;
USHORT usDisk;
DosQCurDisk (&usDisk, &ulDrives); /* gets current drive */
return (unsigned int)usDisk;
#else
unsigned int CurrentDrive;
_dos_getdrive (&CurrentDrive);
return CurrentDrive;
#endif
}
/*
* Set the current drive number and return the number of drives.
*/
unsigned int SetCurrentDrive (unsigned int drive)
{
#ifdef OS2
ULONG ulDrives;
USHORT usDisk;
int i;
DosSelectDisk ((USHORT)drive);
/* Get the current disk and check that to see the number of drives */
DosQCurDisk (&usDisk, &ulDrives); /* gets current drive */
for (i = 25; (!(ulDrives & (1L << i))) && i >= 0; --i)
continue;
return (unsigned int) i + 1;
#else
unsigned int ndrives;
_dos_setdrive (drive, &ndrives);
return ndrives;
#endif
}
/*
* Get and process configuration line:
*
* <field> = <field> <field> # comment
*
* return the number of fields found.
*/
int ExtractFieldsFromLine (LineFields *fd)
{
char *cp;
int len;
Word_B *wb;
if (fgets (fd->Line, fd->LineLength - 1, fd->FP) == (char *)NULL)
{
fclose (fd->FP);
return -1;
}
/* Remove the EOL */
if ((cp = strchr (fd->Line, '\n')) != (char *)NULL)
*cp = 0;
/* Remove the comments at end */
if ((cp = strchr (fd->Line, '#')) != (char *)NULL)
*cp = 0;
/* Extract the fields */
if (fd->Fields != (Word_B *)NULL)
fd->Fields->w_nword = 0;
fd->Fields = SplitString (fd->Line, fd->Fields);
if ((fd->Fields == (Word_B *)NULL) || (fd->Fields->w_nword < 2))
return 1;
/* Check for =. At end of first field? */
wb = fd->Fields;
len = strlen (wb->w_words[0]) - 1;
if (wb->w_words[0][len] == '=')
wb->w_words[0][len] = 0;
/* Check second field for just being equals */
else if (wb->w_nword < 3)
wb->w_nword = 1;
if (strcmp (wb->w_words[1], "=") == 0)
{
(wb->w_nword)--;
memcpy ((void *)(wb->w_words + 1), (void *)(wb->w_words + 2),
(wb->w_nword - 1) * sizeof (void *));
}
/* Check the third field for starting with an equals */
else if (*(wb->w_words[2]) == '=')
strcpy (wb->w_words[2], wb->w_words[2] + 1);
else
wb->w_nword = 1;
return wb->w_nword;
}
/*
* Split the string up into words
*/
Word_B *SplitString (char *string, Word_B *wb)
{
while (*string)
{
while (isspace (*string))
*(string++) = 0;
if (*string)
wb = AddWordToBlock (string, wb);
while (!isspace (*string) && *string)
++string;
}
return wb;
}
/*
* Test to see if a file is a directory
*/
bool IsDirectory (char *Name)
{
struct stat s;
return ((stat (Name, &s) == 0) && S_ISDIR (s.st_mode & S_IFMT))
? TRUE : FALSE;
}
/*
* Check that filename conforms to DOS format. Convert additional .'s to ~.
*/
char *CheckDOSFileName (char *name)
{
char *s;
char *s1;
int count = 0;
/* Find start of file name */
if ((s = strrchr (name, CHAR_UNIX_DIRECTORY)) == (char *)NULL)
s = name;
else
++s;
/* Skip over the directory entries */
if ((strcmp (s, ".") == 0) || (strcmp (s, "..") == 0))
/*SKIP*/;
/* Name starts with a dot? */
else if (*s == '.')
count = 2;
/* Count the number of dots */
else
{
s1 = s;
while ((s1 = strchr (s1, '.')) != (char *)NULL)
{
count++;
s1++;
}
}
/* Check the dot count */
if (count > 1)
{
if (FL_TEST ('w'))
fprintf (stderr, "sh: File <%s> has too many dots, changed to ",
name);
/* Transform the very first if necessary */
if (*s == '.')
*s = '~';
s1 = s;
count = 0;
/* Convert all except the first */
while ((s1 = strchr (s1, '.')) != (char *)NULL)
{
if (++count != 1)
*s1 = '~';
*s1++;
}
if (FL_TEST ('w'))
PrintWarningMessage ("<%s>\n", name);
}
/* Check for double slashes */
s = name;
while ((s = strchr (s, CHAR_UNIX_DIRECTORY)) != (char *)NULL)
{
if (*(++s) == CHAR_UNIX_DIRECTORY)
strcpy (s, s + 1);
}
return name;
}
/*
* Get a valid numeric value
*/
bool ConvertNumericValue (char *string, long *value, int base)
{
char *ep;
*value = strtol (string, &ep, base);
return (*ep) ? FALSE : TRUE;
}